/** file nbarts.cpp
    author belot.nicolas
*/

#include "nbarts.h"

#include <stdint.h>
#include <cmath>
#include <iostream>
#define INT16_MAX              (32767)


namespace libtrckr {

	nbarts_cb_t* _callback;
	pthread_t thread[2];
	void *extarg;
	bool open=false;
	double in[2048];
	int16_t _buffer[2048];
	bool full=false;

	pthread_mutex_t mutin;
	pthread_mutex_t mutcount;
	pthread_cond_t isFull;
	pthread_cond_t isEmpty;

	void *_write(void *arg){
		int errorcode;
		arts_stream_t stream = (arts_stream_t)arg;
		while(open){
			if(full){
				for(int i=0;i<2048;i++){
					_buffer[i]=floor(in[i]*INT16_MAX);
				}
				full=false;
				pthread_testcancel();
				errorcode=arts_write(stream, _buffer, (sizeof(int16_t)*2048));
				if(arts_suspended()){
					std::cout << "arts suspended" << std::endl;
				}
				//std::cout << errorcode << std::endl;
				if(errorcode<0){
					std::cerr << arts_error_text(errorcode) << std::endl;
				}	

			}else{
				if(_callback(1024,extarg)>0){//2 channel
					full=true;
				}else{
					usleep(10000);
				}
			}
			pthread_testcancel();
		}
		pthread_exit(NULL);
	}

	void *_fill(void *arg){
		while(open){
			pthread_mutex_lock(&mutcount);
			if(full){
				pthread_cond_signal(&isFull);
				std::cout << "fill : waiting" << std::endl;
				pthread_cond_wait(&isEmpty,&mutcount);
				std::cout << "fill : active" << std::endl;
			}else{
				pthread_mutex_lock(&mutin);
				if(_callback(1024,extarg)>0){//2 channel
					pthread_mutex_unlock(&mutin);
					full=true;
				}else{
					pthread_mutex_unlock(&mutin);
					std::cout << "sleeping a while" << std::endl;
					usleep(10000);
				}
			}
			pthread_mutex_unlock(&mutcount);
			pthread_testcancel();
		}
		pthread_exit(NULL);
	}
	

	double *getIn(){
		return in;
	}

	arts_stream_t nbarts_get_stream( ){
		while(open) sleep(1);
		arts_stream_t stream;
		int errorcode=arts_init();
		if (errorcode < 0){
        		std::cerr << "Arts Error : " << arts_error_text(errorcode) << std::endl;
        		return NULL;
    		}
		stream=arts_play_stream(44100, 16, 2, "trckr1out");
		//arts_stream_set(stream,ARTS_P_BLOCKING,0);
		std::cout << "aRts blocking : " << arts_stream_get(stream, ARTS_P_BLOCKING) << std::endl;
		open=true;
		/*pthread_mutex_init(&mutcount,NULL);
		pthread_mutex_init(&mutin,NULL);
		pthread_cond_init(&isFull,NULL);
		pthread_cond_init(&isEmpty,NULL);*/
		pthread_create(&thread[0],NULL,_write,(void*) stream);
		//pthread_create(&thread[1],NULL,_fill, NULL);
		return stream;
	} 
	
	void nbarts_close_stream(arts_stream_t stream){
		//stop thread before closing stream...
		pthread_cancel(thread[0]);
		//pthread_cancel(thread[1]);
		pthread_join(thread[0],NULL);
		arts_close_stream(stream);
		arts_free();
		open=false;
	}

	int nbarts_set_callback(nbarts_cb_t *cb,void *anarg){
		_callback=cb;
		extarg=anarg;
	}

}
